use crate::rtsp::marshal_trait::{Marshal, Unmarshal};
use base64::engine::general_purpose;
use base64::Engine;
use bytes::{BufMut, BytesMut};

// H264 视频格式的 Fmtp 结构体
#[derive(Debug, Clone, Default)]
pub struct H264Fmtp {
    // 负载类型
    pub payload_type: u16,
    // 包封装模式
    packetization_mode: u8,
    // 配置文件级别 ID
    profile_level_id: BytesMut,
    // 序列化参数集
    pub sps: BytesMut,
    // 图像参数集
    pub pps: BytesMut,
}

impl Unmarshal for H264Fmtp {
    fn unmarshal(raw_data: &str) -> Option<Self> {
        let mut h264_fmtp = H264Fmtp::default();
        // 按空格分割字符串，获取负载类型和参数部分
        let eles: Vec<&str> = raw_data.splitn(2, ' ').collect();
        if eles.len() < 2 {
            log::warn!("H264FmtpSdp parse err: {}", raw_data);
            return None;
        }

        // 尝试解析负载类型
        if let Ok(payload_type) = eles[0].parse::<u16>() {
            h264_fmtp.payload_type = payload_type;
        }

        // 按分号分割参数部分，获取每个参数
        let parameters: Vec<&str> = eles[1].split(';').collect();
        for parameter in parameters {
            // 按等号分割参数，获取键值对
            let kv: Vec<&str> = parameter.trim().splitn(2, '=').collect();
            if kv.len() < 2 {
                log::warn!("H264FmtpSdp parse key=value err: {}", parameter);
                continue;
            }
            match kv[0] {
                "packetization-mode" => {
                    // 解析包封装模式
                    if let Ok(packetization_mode) = kv[1].parse::<u8>() {
                        h264_fmtp.packetization_mode = packetization_mode;
                    }
                }
                "sprop-parameter-sets" => {
                    // 解析 SPS 和 PPS
                    let spspps: Vec<&str> = kv[1].split(',').collect();
                    let sps = general_purpose::STANDARD.decode(spspps[0]).unwrap();
                    h264_fmtp.sps.put(&sps[..]);
                    let pps = general_purpose::STANDARD.decode(spspps[1]).unwrap();
                    h264_fmtp.pps.put(&pps[..]);
                }
                "profile-level-id" => {
                    // 解析配置文件级别 ID
                    h264_fmtp.profile_level_id = kv[1].into();
                }
                _ => {
                    log::info!("not parsed: {}", kv[0])
                }
            }
        }

        Some(h264_fmtp)
    }
}

impl Marshal for H264Fmtp {
    fn marshal(&self) -> String {
        // 对 SPS 和 PPS 进行 base64 编码
        let sps_str = general_purpose::STANDARD.encode(&self.sps);
        let pps_str = general_purpose::STANDARD.encode(&self.pps);
        // 将配置文件级别 ID 转换为字符串
        let profile_level_id_str = String::from_utf8(self.profile_level_id.to_vec()).unwrap();

        // 格式化字符串
        let h264_fmtp = format!(
            "{} packetization-mode={}; sprop-parameter-sets={},{}; profile-level-id={}",
            self.payload_type, self.packetization_mode, sps_str, pps_str, profile_level_id_str
        );

        // 添加换行符
        format!("{h264_fmtp}\r\n")
    }
}

// H265 视频格式的 Fmtp 结构体
#[derive(Debug, Clone, Default)]
pub struct H265Fmtp {
    // 负载类型
    pub payload_type: u16,
    // 视频参数集
    pub vps: BytesMut,
    // 序列化参数集
    pub sps: BytesMut,
    // 图像参数集
    pub pps: BytesMut,
}

impl Unmarshal for H265Fmtp {
    fn unmarshal(raw_data: &str) -> Option<Self> {
        let mut h265_fmtp = H265Fmtp::default();
        // 按空格分割字符串，获取负载类型和参数部分
        let eles: Vec<&str> = raw_data.splitn(2, ' ').collect();
        if eles.len() < 2 {
            log::warn!("H265FmtpSdp parse err: {}", raw_data);
            return None;
        }

        // 尝试解析负载类型
        if let Ok(payload_type) = eles[0].parse::<u16>() {
            h265_fmtp.payload_type = payload_type;
        }

        // 按分号分割参数部分，获取每个参数
        let parameters: Vec<&str> = eles[1].split(';').collect();
        for parameter in parameters {
            // 按等号分割参数，获取键值对
            let kv: Vec<&str> = parameter.trim().splitn(2, '=').collect();
            if kv.len() < 2 {
                log::warn!("H265FmtpSdp parse key=value err: {}", parameter);
                continue;
            }

            match kv[0] {
                "sprop-vps" => {
                    // 解析 VPS
                    h265_fmtp.vps = kv[1].into();
                }
                "sprop-sps" => {
                    // 解析 SPS
                    h265_fmtp.sps = kv[1].into();
                }
                "sprop-pps" => {
                    // 解析 PPS
                    h265_fmtp.pps = kv[1].into();
                }
                _ => {
                    log::info!("not parsed: {}", kv[0])
                }
            }
        }

        Some(h265_fmtp)
    }
}

impl Marshal for H265Fmtp {
    fn marshal(&self) -> String {
        // 将 VPS、SPS 和 PPS 转换为字符串
        let sps_str = String::from_utf8(self.sps.to_vec()).unwrap();
        let pps_str = String::from_utf8(self.pps.to_vec()).unwrap();
        let vps_str = String::from_utf8(self.vps.to_vec()).unwrap();

        // 格式化字符串
        let h265_fmtp = format!(
            "{} sprop-vps={}; sprop-sps={}; sprop-pps={}",
            self.payload_type, vps_str, sps_str, pps_str
        );

        // 添加换行符
        format!("{h265_fmtp}\r\n")
    }
}

// MPEG-4 音频格式的 Fmtp 结构体
#[derive(Debug, Clone, Default)]
pub struct Mpeg4Fmtp {
    // 负载类型
    pub payload_type: u16,
    // 音频特定配置
    pub asc: BytesMut,
    // 配置文件级别 ID
    profile_level_id: BytesMut,
    // 音频编码模式
    mode: String,
    // 数据大小长度
    size_length: u16,
    // 索引长度
    index_length: u16,
    // 索引增量长度
    index_delta_length: u16,
}

impl Unmarshal for Mpeg4Fmtp {
    fn unmarshal(raw_data: &str) -> Option<Self> {
        let mut mpeg4_fmtp = Mpeg4Fmtp::default();
        // 按空格分割字符串，获取负载类型和参数部分
        let eles: Vec<&str> = raw_data.splitn(2, ' ').collect();
        if eles.len() < 2 {
            log::warn!("Mpeg4FmtpSdp parse err: {}", raw_data);
            return None;
        }

        // 尝试解析负载类型
        if let Ok(payload_type) = eles[0].parse::<u16>() {
            mpeg4_fmtp.payload_type = payload_type;
        }

        // 按分号分割参数部分，获取每个参数
        let parameters: Vec<&str> = eles[1].split(';').collect();
        for parameter in parameters {
            // 按等号分割参数，获取键值对
            let kv: Vec<&str> = parameter.trim().splitn(2, '=').collect();
            if kv.len() < 2 {
                log::warn!("Mpeg4FmtpSdp parse key=value err: {}", parameter);
                continue;
            }
            match kv[0].to_lowercase().as_str() {
                "mode" => {
                    // 解析音频编码模式
                    mpeg4_fmtp.mode = kv[1].to_string();
                }
                "config" => {
                    // 解析音频特定配置
                    let asc = hex::decode(kv[1]).unwrap();
                    mpeg4_fmtp.asc.put(&asc[..]);
                }
                "profile-level-id" => {
                    // 解析配置文件级别 ID
                    mpeg4_fmtp.profile_level_id = kv[1].into();
                }
                "sizelength" => {
                    // 解析数据大小长度
                    if let Ok(size_length) = kv[1].parse::<u16>() {
                        mpeg4_fmtp.size_length = size_length;
                    }
                }
                "indexlength" => {
                    // 解析索引长度
                    if let Ok(index_length) = kv[1].parse::<u16>() {
                        mpeg4_fmtp.index_length = index_length;
                    }
                }
                "indexdeltalength" => {
                    // 解析索引增量长度
                    if let Ok(index_delta_length) = kv[1].parse::<u16>() {
                        mpeg4_fmtp.index_delta_length = index_delta_length;
                    }
                }
                _ => {
                    log::info!("not parsed: {}", kv[0])
                }
            }
        }

        Some(mpeg4_fmtp)
    }
}

impl Marshal for Mpeg4Fmtp {
    fn marshal(&self) -> String {
        // 将配置文件级别 ID 转换为字符串
        let profile_level_id_str = String::from_utf8(self.profile_level_id.to_vec()).unwrap();
        // 对音频特定配置进行十六进制编码
        let asc_str = hex::encode(&self.asc);

        // 格式化字符串，包含所有必要的 MPEG - 4 Fmtp 参数
        let mpeg4_fmtp = format!(
            "{} profile - level - id={};mode={};sizelength={};indexlength={};indexdeltalength={}; config={}",
            self.payload_type, profile_level_id_str, self.mode, self.size_length, self.index_length,
            self.index_delta_length, asc_str
        );

        // 添加换行符
        format!("{mpeg4_fmtp}\r\n")
    }
}

// Fmtp 枚举
#[derive(Debug, Clone)]
pub enum Fmtp {
    H264(H264Fmtp),
    H265(H265Fmtp),
    Mpeg4(Mpeg4Fmtp),
}

impl Fmtp {
    pub fn new(codec: &str, raw_data: &str) -> Option<Fmtp> {
        match codec.to_lowercase().as_str() {
            "h264" => {
                if let Some(h264_fmtp) = H264Fmtp::unmarshal(raw_data) {
                    return Some(Fmtp::H264(h264_fmtp));
                }
            }
            "h265" => {
                if let Some(h265_fmtp) = H265Fmtp::unmarshal(raw_data) {
                    return Some(Fmtp::H265(h265_fmtp));
                }
            }
            "mpeg4-generic" => {
                if let Some(mpeg4_fmtp) = Mpeg4Fmtp::unmarshal(raw_data) {
                    return Some(Fmtp::Mpeg4(mpeg4_fmtp));
                }
            }
            _ => {}
        }
        None
    }

    pub fn marshal(&self) -> String {
        match self {
            Fmtp::H264(f) => f.marshal(),
            Fmtp::H265(f) => f.marshal(),
            Fmtp::Mpeg4(f) => f.marshal(),
        }
    }
}
